#pragma once
#include <pthread.h>
#include <iostream>
#include <unistd.h>
#include <queue>

namespace BlockQueueModule
{
    template<typename T>
    class BlockQueue
    {
    private:
        bool IsFool(){return _blockqueue.size() == _cap;}
        bool IsEmpty(){return _blockqueue.empty();}
    public:
        //构造函数
        BlockQueue(int cap):_cap(cap)
        {
            //初始化条件变量和互斥锁
            pthread_mutex_init(&_mutex,nullptr);
            pthread_cond_init(&_p_cond,nullptr);
            pthread_cond_init(&_c_cond,nullptr);
        }
        //入队列操作---需要传入一个固定参数
        void Equeue(const T& in)
        {
            pthread_mutex_lock(&_mutex);
            if(IsFool())
            {
                //等待时
                _p_num++;
                //在指定条件变量在等待
                pthread_cond_wait(&_p_cond,&_mutex);
                //等待后
                _p_num--;
            }
            //生产者线程被唤醒 || 阻塞队列没有满
            _blockqueue.push(in);

            //生产数据之后有消费者在等待----唤醒消费者
            if(_c_num != 0)
            {
                pthread_cond_signal(&_c_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        //出队列操作---需要传入指针将数据带出
        void Pop(T* out)
        {
            pthread_mutex_lock(&_mutex);
            if(IsEmpty())
            {
                _c_num++;
                pthread_cond_wait(&_c_cond,&_mutex);
                _c_num--;
            }
            //被唤醒 || 不为空
            *out = _blockqueue.back();
            _blockqueue.pop();
            if(_p_num != 0)
            {
                pthread_cond_signal(&_p_cond);
            }
            pthread_mutex_unlock(&_mutex);
        }
        ~BlockQueue()
        {
            //销毁互斥锁和条件变量
            pthread_mutex_destroy(&_mutex);
            pthread_cond_destroy(&_p_cond);
            pthread_cond_destroy(&_c_cond);
        }
    private:
        int _cap;                       //阻塞队列的固定大小
        std::queue<T> _blockqueue;      //阻塞队列
        pthread_mutex_t _mutex;         //锁资源----维护消费者和生产者的互斥关系

        pthread_cond_t _p_cond;         //条件变量---生产者等待的条件变量
        pthread_cond_t _c_cond;         //条件变量---消费者等待的条件变量

        int _p_num;                     //正在等待的消费者
        int _c_num;                     //正在等待的生产者
    };
}